已經到了鐵人賽最後二天了,今天的主題方向和之前會有一些不太相同,要和大家說明在OpenStack網路裡,Trunk的功能是如何實現的。先來看一下官方文件對於Trunk的定義吧。
The network trunk service allows multiple networks to be connected to an instance using a single virtual NIC (vNIC). Multiple networks can be presented to an instance by connecting it to a single port.
對照之前的介紹,當VM連至一個Network時,Network上會有一個Port,這個Port的attached device是comppute: nova
,在VM就可以看到一張NIC連到這一個Port;如果VM要連至多個Network時,VM裡會有多個NIC,每個NIC都是連到OpenStack上的某一個Port. 這會衍生二個明顯的問題:
為了達成單獨使用一個NIC,完成讓VM自行管理連到那幾個Network上,就引用了VLAN Trunk的想法,在VM的一個NIC上(eg. eth0),可以配置多個VLAN ID(eg. eth0.100, eth.200...),每個VLAN對應至不同的Network。VM本身可以透過設定sub interface,自行決定要和那些Network相連。
Neutron Trunking是讓VM可以自行動態的設定要與那幾個Network相連,但在OpenStack上,仍然要事先建立Network與Port。所以對照二種模式,Port的數量與Netwrok數量是相同的。但VM只有一個NIC,可以依照需求,建立sub interface。
Legancy | Trunk |
---|---|
因為Neutron Trunking是使用 VLAN 的概念來達到讓一個VM使用一個NIC連接到多個Network,由圖可以看到,會有不同VLAN的封包在VM的NIC上傳送。致於要如何讓VM上帶有VLAN tag的封包如何透過實體網路,送到不同實體主機上的VM上,在OpenStack 社群裡提出二個方案:
如果要讓VM能使用Trunk,和VM相關的網路設定有很大的不同,我們來看一下整個過程要做那些變動:
openstack network create parent
openstack network create child1
特別注意這邊建立Network時,network type不必選VLAN,OVN會透過logical flow,去模擬出好像有VLAN 的封包的行為。
openstack subnet create --network parent --subnet-range 10.0.11.0/24 parent_subnet
openstack subnet create --network child1 --subnet-range 10.0.22.0/24 child1_subnet
openstack port create --network parent parent0
parent_mac="$( openstack port show parent0 | awk '/ mac_address / { print $4 }' )"
openstack port create --network child1 --mac-address "$parent_mac" child1
在建立child port時,我們手動指定child port和parent port有相同的MAC addrsss。這是因為在稍後,我們會在VM裡建立綁在eth0上的sub interface,Linux的行為是sub interface的MAC addr會和原本的interface相同。因為instance 的eth0的MAC addr是由parent port決定的,所以,建child port時,指定child port的MAC和parent port相同。如此一來,child port、parent port、eth0、eth0.XXX的MAC都會完全相同
openstack network trunk create --parent-port parent0 trunk0
openstack network trunk set --subport port=child1,segmentation-type=vlan,segmentation-id=100 trunk0
IMAGE_ID=$(openstack image show cirros --format json | jq -r .id)
parent_port_id=`openstack port list --name parent0 -f value -c ID`
openstack server create --nic port-id=${parent_port_id} --flavor m1.nano --image $IMAGE_ID vm_1
ip link add link eth0 name eth0.200 type vlan id 100
ip link set eth0.100 up
penstack port create --network parent parenta
arent_mac="$( openstack port show parenta | awk '/ mac_address / { print $4 }' )"
penstack port create --network child1 --mac-address "$parent_mac" childb
penstack network trunk create --parent-port parenta --subport port=childb,segmentation-type=vlan,segmentation-id=100 trunk1
arent_port_id=`openstack port list --name parenta -f value -c ID`
penstack server create --nic port-id=${parent_port_id} --flavor m1.nano --image $IMAGE_ID vm_2
``
p link add link eth0 name eth0.100 type vlan id 100
p link set eth0.100 up
``
查看OpenStack上Network 、Trunk、Port的資訊,確實與圖中預期要建立的長像是相同的
# Network
openstack network list --long -c ID -c "Network Type" | abbrev
+--------+--------------+
| ID | Network Type |
+--------+--------------+
| 624780 | geneve |
| 91a36d | geneve |
+--------+--------------+
# Server
openstack serve list --long -c Name -c Networks | abbrev
+------+-------------------+
| Name | Networks |
+------+-------------------+
| vm_2 | parent=10.0.11.21 |
| vm_1 | parent=10.0.11.4 |
+------+-------------------+
# Trunk
openstack network trunk list
+--------+--------+-------------+-------------+
| ID | Name | Parent Port | Description |
+--------+--------+-------------+-------------+
| 1c5b0a | trunk0 | 0fd168 | |
| cacf0e | trunk1 | e21fe6 | |
+--------+--------+-------------+-------------+
# Port
openstack port list --long -c ID -c "MAC Address" -c "Fixed IP Addresses" -c "Device Owner" | abbrev
+--------+-------------------+----------------------------------------------+---------------------+
| ID | MAC Address | Fixed IP Addresses | Device Owner |
+--------+-------------------+----------------------------------------------+---------------------+
| 424bc4 | fa:16:3e:d6:85:ec | ip_address='10.0.22.2', subnet_id='03ec93' | network:distributed |
| c49d3b | fa:16:3e:68:61:12 | ip_address='10.0.11.2', subnet_id='e39d80' | network:distributed |
| 70789a | fa:16:3e:d5:3c:74 | ip_address='10.0.22.187', subnet_id='03ec93' | trunk:subport |
| e21fe6 | fa:16:3e:d5:3c:74 | ip_address='10.0.11.21', subnet_id='e39d80' | compute:nova |
| 0fd168 | fa:16:3e:47:ae:23 | ip_address='10.0.11.4', subnet_id='e39d80' | compute:nova |
| 7c5a44 | fa:16:3e:47:ae:23 | ip_address='10.0.22.225', subnet_id='03ec93' | trunk:subport |
+--------+-------------------+----------------------------------------------+---------------------+
我們來看一下在OVN上,有那些logical switch被建立出來。因為在OpenStack上有二個Geneve Network,所以可以看到有二個logical switch。這二個switch分別連到VM上的二個不同的NIC。唯一的不同點,在於做為child network的logical switch上,logical switch port上,可以看到tag的屬性,表示通過這個port的封包都會帶有VLAN tag,而在VM上,就會連到相對應的VLAN NIC。如果二個VM是透過parent network網段溝通的話,會使用左邊的logical switch;反之,如果是用child network網段溝通的話,會使用右邊的switch。
ovn-nbctl show | abbrev
switch 6738bc (neutron-91a36d) (aka child1)
port 5aee74 (aka child1)
parent: 7fb5cc
tag: 100
addresses: ["fa:16:3e:47:ae:23 10.0.22.225"]
port 30ed0e
type: localport
addresses: ["fa:16:3e:d6:85:ec 10.0.22.2"]
port 70789a (aka childb)
parent: 7ad541
tag: 100
addresses: ["fa:16:3e:d5:3c:74 10.0.22.187"]
switch bafb8c (neutron-f32d30) (aka parent)
port 7ad541 (aka parenta)
addresses: ["fa:16:3e:d5:3c:74 10.0.11.21"]
port 051a81
type: localport
addresses: ["fa:16:3e:68:61:12 10.0.11.2"]
port 7fb5cc (aka parent0)
addresses: ["fa:16:3e:47:ae:23 10.0.11.4"]